package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.srb.base.asserts.Asserts;
import com.atguigu.srb.base.dto.SmsDTO;
import com.atguigu.srb.base.response.ResponseEnum;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.core.hfb.*;
import com.atguigu.srb.core.pojo.entity.TransFlow;
import com.atguigu.srb.core.pojo.entity.UserAccount;
import com.atguigu.srb.core.mapper.UserAccountMapper;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.service.TransFlowService;
import com.atguigu.srb.core.service.UserAccountService;
import com.atguigu.srb.core.service.UserInfoService;
import com.atguigu.srb.mq.consts.MqConsts;
import com.atguigu.srb.mq.service.MqService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 用户账户 服务实现类
 * </p>
 *
 * @author Atguigu
 * @since 2023-05-26
 */
@Service
@Slf4j
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {
    @Resource
    UserInfoService userInfoService;
    @Resource
    TransFlowService transFlowService;
    @Resource
    MqService mqService;
    @Override
    public UserAccount getUserAccountByBindCode(String bindCode) {
        //先查询userInfo表 id
        //再根据userid查询UserAccount
        //也可以自定义sql:
        return baseMapper.selectUserAccountByBindCode(bindCode);
    }
    //查询账户余额业务
    @Override
    public BigDecimal getAmount(String token) {
        Long userId = JwtUtils.getUserId(token);
        UserAccount account = this.getOne(Wrappers.lambdaQuery(UserAccount.class)
                .eq(UserAccount::getUserId, userId));
        return account.getAmount();
    }

    @Override
    public BigDecimal getInterestCount(BigDecimal invest, Integer period, BigDecimal yearRate, Integer returnMethod) {
        BigDecimal amount = null;

        //判断还款方式：选择计算收益的方式
        switch (returnMethod){
            case 1:
                amount = Amount1Helper.getInterestCount(invest,yearRate.divide(new BigDecimal(100),8,
                        BigDecimal.ROUND_DOWN),period);
                break;
            case 2:
                amount = Amount2Helper.getInterestCount(invest,yearRate.divide(new BigDecimal(100),8,
                        BigDecimal.ROUND_DOWN),period);
                break;
            case 3:
                amount = Amount3Helper.getInterestCount(invest,yearRate.divide(new BigDecimal(100),8,
                        BigDecimal.ROUND_DOWN),period);
                break;
            case 4:
                amount = Amount4Helper.getInterestCount(invest,yearRate.divide(new BigDecimal(100),8,
                        BigDecimal.ROUND_DOWN),period);
                break;
        }
        return amount;
    }

    @Override
    public void updateInvestAmountByUserId(BigDecimal transAmount, Long userId) {
        baseMapper.updateInvestAmountByUserId(transAmount,userId);
    }

    @Override
    public void updateFreezeAmountByUserId(Long investUserId, BigDecimal investAmount) {

        baseMapper.updateFreezeAmountByUserId(investUserId,investAmount);

    }
    /*
        restful风格
        查询：
            单个对象的key
            对象集合的key
            map的key
            布尔值的key
            基本类型数值的key
            规范稍微一致
        增删改：
            开发中可以返回增删改后的对象
        统一响应类
     */
    @Override
    public String withDraw(String token, BigDecimal amount) {
        // 校验账户安全
        UserInfo userInfo = userInfoService.checkAccount(token);
        // 判断账户余额是否足够
        BigDecimal accountAmount = this.getAmount(token);
        Asserts.assertNotTrue(accountAmount.compareTo(amount)<0,
                ResponseEnum.DRAW_AMOUNT_ERROR );
        // 构建自动提交的表单字符串
        Map<String, Object> params = new HashMap<>();
        params.put("agentId", HfbConst.AGENT_ID);
        // LendNoUtils.getWithdrawNo():
        //交易的单号：
        String withdrawNo = LendNoUtils.getWithdrawNo();
        params.put("agentBillNo", withdrawNo);
        //提现会员的hfb账户：
        params.put("bindCode",userInfo.getBindCode());
        //提现时不扣除手续费： 借款人还款时，给投资人回款时扣除回款手续费
        params.put("fetchAmt",amount);
        params.put("feeAmt",new BigDecimal(0));
        params.put("returnUrl",HfbConst.WITHDRAW_RETURN_URL);
        // 地址需要能访问到nginx
        params.put("notifyUrl",HfbConst.WITHDRAW_NOTIFY_URL);
        params.put("timestamp",System.currentTimeMillis());
        params.put("sign",RequestHelper.getSign(params));

        //保存交易日志
        TransFlow transFlow = new TransFlow();
        transFlow.setUserId(userInfo.getId());
        transFlow.setUserName(userInfo.getName());
        // 交易流水号，可以使用本次交易的唯一编号设置
        transFlow.setTransNo(withdrawNo);
        transFlow.setTransType(2);
        transFlow.setTransTypeName("提现");
        transFlow.setTransAmount(amount);
        transFlow.setStatus(0);
        transFlowService.save(transFlow);

        return FormHelper.buildForm(HfbConst.WITHDRAW_URL,params);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String notifyWithdraw(HttpServletRequest request) {
        Map<String, Object> map = RequestHelper.switchMap(request.getParameterMap());
        //1、校验签名
        if(!RequestHelper.isSignEquals(map)){
            log.error("提现失败,签名错误：{}", JSON.toJSONString(map));
            return "fail";
        }
        //2、验证状态码
        if(!StringUtils.equals("0001",map.get("resultCode").toString())){
            log.error("提现失败,hfb业务错误：{}", JSON.toJSONString(map));
            return "fail";
        }
        //3、幂等性：使用交易流水编号
        // 上一步必须将交易日志保存到交易流水表中
        String agentBillNo = map.get("agentBillNo").toString();
        TransFlow transFlow = transFlowService.getTransFlowByAgentBillNo(agentBillNo);
        if(transFlow==null){
            log.error("提现失败,非法请求：{}", JSON.toJSONString(map));
            return "fail";
        }
        if(transFlow!=null && transFlow.getStatus()!=0){
            return "success";
        }
        //4、校验提现金额
        if(transFlow.getTransAmount().compareTo(new BigDecimal(map.get("fetchAmt").toString()))!=0){
            log.error("提现失败,提现金额错误：{}", JSON.toJSONString(map));
            return "fail";
        }
        //5、更新会员本地账户余额
        UserAccount userAccount = this.getOne(Wrappers.lambdaQuery(UserAccount.class)
                .eq(UserAccount::getUserId, transFlow.getUserId()));
        userAccount.setAmount(userAccount.getAmount().subtract(transFlow.getTransAmount()));
        this.updateById(userAccount);
        //6、更新日志状态
        transFlow.setStatus(1);
        transFlow.setMemo(JSON.toJSONString(map));
        transFlowService.updateById(transFlow);

        //发送消息通知会员提现成功
        UserInfo userInfo = userInfoService.getById(userAccount.getUserId());
        SmsDTO smsDto = new SmsDTO();
        smsDto.setMobile(userInfo.getMobile());
        //充值金额  充值之后的账户余额
        smsDto.setParams(Arrays.asList(transFlow.getTransAmount().toString(),
                userAccount.getAmount().toString()));
        //充值成功: 5
        smsDto.setType(5);
        mqService.sendMsg(MqConsts.EXCHANGE_TOPIC_SMS,MqConsts.ROUTING_SMS_ITEM,smsDto);
        return "success";
    }
}
